/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.usertrace.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import vip.xiaonuo.core.consts.CommonConstant;
import vip.xiaonuo.core.enums.CommonStatusEnum;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PastTimeFormatUtil;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.modular.questionnaire.entity.Questionnaire;
import vip.xiaonuo.modular.questionnaire.service.QuestionnaireService;
import vip.xiaonuo.modular.questionnairedetail.entity.QuestionnaireDetail;
import vip.xiaonuo.modular.questionnairedetail.mapper.QuestionnaireDetailMapper;
import vip.xiaonuo.modular.qusstionnaire.entity.Qusstionnaire;
import vip.xiaonuo.modular.qusstionnaire.service.QusstionnaireService;
import vip.xiaonuo.modular.user.entity.User;
import vip.xiaonuo.modular.user.service.UserService;
import vip.xiaonuo.modular.usertrace.entity.UserTrace;
import vip.xiaonuo.modular.usertrace.enums.UserTraceExceptionEnum;
import vip.xiaonuo.modular.usertrace.mapper.UserTraceMapper;
import vip.xiaonuo.modular.usertrace.param.UserTraceParam;
import vip.xiaonuo.modular.usertrace.service.UserTraceService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 账户流水service接口实现类
 *
 * @author wanglei
 * @date 2021-08-25 18:59:05
 */
@Service
public class UserTraceServiceImpl extends ServiceImpl<UserTraceMapper, UserTrace> implements UserTraceService {


    @Autowired
    private UserTraceMapper userTraceMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private QuestionnaireService questionnaireService;

    @Autowired
    private QuestionnaireDetailMapper questionnaireDetailMapper;


    @Override
    public PageResult<UserTrace> page(UserTraceParam userTraceParam) {
        QueryWrapper<UserTrace> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(userTraceParam)) {
            // 根据操作流水 查询
            if (ObjectUtil.isNotEmpty(userTraceParam.getTraceSn())) {
                queryWrapper.lambda().eq(UserTrace::getTraceSn, userTraceParam.getTraceSn());
            }
            // 根据用户表的用户ID 查询
            if (ObjectUtil.isNotEmpty(userTraceParam.getUserId())) {
                queryWrapper.lambda().eq(UserTrace::getUserId, userTraceParam.getUserId());
            }
            // 根据操作金额 查询
            if (ObjectUtil.isNotEmpty(userTraceParam.getAmount())) {
                queryWrapper.lambda().eq(UserTrace::getAmount, userTraceParam.getAmount());
            }
            // 根据申请时间 查询
            if (ObjectUtil.isNotEmpty(userTraceParam.getAddTime())) {
                queryWrapper.lambda().eq(UserTrace::getAddTime, userTraceParam.getAddTime());
            }
        }
        return new PageResult<>(page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public List<UserTrace> list(UserTraceParam userTraceParam) {
        return this.list();
    }

    @Override
    public void add(UserTraceParam userTraceParam) {
        UserTrace userTrace = new UserTrace();
        BeanUtil.copyProperties(userTraceParam, userTrace);
        this.save(userTrace);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<UserTraceParam> userTraceParamList) {
        userTraceParamList.forEach(userTraceParam -> {
            this.removeById(userTraceParam.getId());
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(UserTraceParam userTraceParam) {
        UserTrace userTrace = this.queryUserTrace(userTraceParam);
        BeanUtil.copyProperties(userTraceParam, userTrace);
        this.updateById(userTrace);
    }

    @Override
    public UserTrace detail(UserTraceParam userTraceParam) {
        return this.queryUserTrace(userTraceParam);
    }

    /**
     * 获取账户流水
     *
     * @author wanglei
     * @date 2021-08-25 18:59:05
     */
    private UserTrace queryUserTrace(UserTraceParam userTraceParam) {
        UserTrace userTrace = this.getById(userTraceParam.getId());
        if (ObjectUtil.isNull(userTrace)) {
            throw new ServiceException(UserTraceExceptionEnum.NOT_EXIST);
        }
        return userTrace;
    }

    @Override
    public void export(UserTraceParam userTraceParam) {
        List<UserTrace> list = this.list(userTraceParam);
        PoiUtil.exportExcelWithStream("SnowyUserTrace.xls", UserTrace.class, list);
    }

    /**
     * 根据用户phone获取所有流水信息
     *
     * @param phone
     * @return
     */
    @Override
    public List<UserTrace> selectByPhones(String phone) {
        QueryWrapper<UserTrace> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserTrace::getPhone, phone);
        return this.list(queryWrapper);
    }

    @Override
    public Map selectAllTurnover(String phone, Integer month) throws ParseException {
        month = month == null ? 0 : month;
        QueryWrapper<UserTrace> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserTrace::getPhone, phone);
        Date startDate = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        switch (month) {
            case 1:
                queryWrapper.gt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getFirstDayOfMonth(startDate.getMonth())));
                queryWrapper.lt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getLastDayOfMonth(startDate.getMonth())));
                break;
            case 3:
                queryWrapper.gt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getFirstDayOfMonth(startDate.getMonth() - 3)));
                queryWrapper.lt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getLastDayOfMonth(startDate.getMonth())));
                break;
            case 6:
                queryWrapper.gt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getFirstDayOfMonth(startDate.getMonth() - 6)));
                queryWrapper.lt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getLastDayOfMonth(startDate.getMonth())));
                break;
            case 12:
                queryWrapper.gt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getFirstDayOfMonth(startDate.getMonth() - 12)));
                queryWrapper.lt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getLastDayOfMonth(startDate.getMonth())));
                break;
            default:
                break;
        }
        List<UserTrace> userTraces = this.list(queryWrapper);
        Map<String, BigDecimal> data = new HashMap<>();
        BigDecimal questionnaire = new BigDecimal(BigInteger.ZERO);
        BigDecimal share = new BigDecimal(BigInteger.ZERO);
        for (UserTrace e : userTraces) {
            if (e.getType() == CommonConstant.QUESTIONNAIRE)
                questionnaire = questionnaire.add(e.getAmount());
            if (e.getType() == CommonConstant.SHARE)
                share = share.add(e.getAmount());
        }
        data.put("questionnaire", questionnaire);
        data.put("share", share);
        return data;
    }

    /**
     * 根据用户手机号统计数据资产
     */
    @Override
    public Map property(String phone, Integer month) throws ParseException {
        month = month == null ? 0 : month;
        QueryWrapper<UserTrace> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserTrace::getPhone, phone);
        int months = DateUtil.thisMonth();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        switch (month) {
            case 1:
                queryWrapper.gt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getFirstDayOfMonth(months)));
                queryWrapper.lt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getLastDayOfMonth(months)));
                break;
            case 3:
                queryWrapper.gt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getFirstDayOfMonth(months - 3)));
                queryWrapper.lt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getLastDayOfMonth(months)));
                break;
            case 6:
                queryWrapper.gt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getFirstDayOfMonth(months - 6)));
                queryWrapper.lt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getLastDayOfMonth(months)));
                break;
            case 12:
                queryWrapper.gt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getFirstDayOfMonth(months - 12)));
                queryWrapper.lt("add_time", simpleDateFormat.parse(PastTimeFormatUtil.getLastDayOfMonth(months)));
                break;
            default:
                break;
        }
        List<UserTrace> userTraces = this.list(queryWrapper);
        Map<String, BigDecimal> data = new HashMap<>();
        BigDecimal questionnaire = new BigDecimal(BigInteger.ZERO);
        BigDecimal share = new BigDecimal(BigInteger.ZERO);
        for (UserTrace e : userTraces) {
            if (e.getSource() == CommonConstant.QUESTIONNAIRE)//问卷填写
                questionnaire = questionnaire.add(e.getAmount());
            if (e.getSource() == CommonConstant.SHARE)//分享获佣
                share = share.add(e.getAmount());
        }
        data.put("questionnaire", questionnaire);
        data.put("share", share);
        return data;
    }


    @Override
    public Map getTodaySWithdrawalLimit(String phone) {
        List<UserTrace> userTraces = this.selectByPhone(phone);
        Map<String, BigDecimal> params = new HashMap<>();
        BigDecimal withdrawn = new BigDecimal(BigInteger.ZERO);
        if (ObjectUtil.isEmpty(userTraces)) {
            params.put("wxWithdrawalAmount", BigDecimal.valueOf(1000));
            return params;
        }
        for (UserTrace userTrace : userTraces) {
            if (userTrace.getSource() == CommonConstant.WITHDRAW)
                withdrawn = withdrawn.add(userTrace.getAmount());
        }
        log.debug("已提现金额：=" + withdrawn);
        params.put("wxWithdrawalAmount", BigDecimal.valueOf(1000).subtract(withdrawn));
        return params;
    }

    @Override
    public List<UserTrace> selectByPhone(String phone) {
        return userTraceMapper.selectByPhone(phone);
    }

    @Override
    public Map getLumpSum(String phone) {
        QueryWrapper<UserTrace> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserTrace::getPhone, phone);
        List<UserTrace> userTraces = this.list(queryWrapper);
        HashMap<String, Object> hashMap = Maps.newHashMap();
        BigDecimal questionnaire = new BigDecimal(BigInteger.ZERO);
        BigDecimal subCommission = new BigDecimal(BigInteger.ZERO);
        for (UserTrace userTrace : userTraces) {
            if (userTrace.getSource() == 0)
                questionnaire = questionnaire.add(userTrace.getAmount());
            if (userTrace.getSource() == 1)
                subCommission = subCommission.add(userTrace.getAmount());
        }
        hashMap.put("questionnaire", questionnaire);
        hashMap.put("subCommission", subCommission);
        hashMap.put("total", questionnaire.add(subCommission));
        return hashMap;
    }

    /**
     * 流水操作
     *
     * @param phone
     * @param questionnaireId
     */
    @Override
    public void createDistribution(String phone, Long questionnaireId) {
        User user = userService.getByPhone(phone);
        if (ObjectUtil.isEmpty(user))
            throw new ServiceException(HttpStatus.HTTP_NOT_FOUND, "未查询到用户信息");
//        Questionnaire questionnaire = questionnaireService.getById(questionnaireId);
        Long mainId = questionnaireDetailMapper.selectById(questionnaireId).getMainId();
        Questionnaire questionnaire = questionnaireService.getById(mainId);
        if (ObjectUtil.isEmpty(questionnaire))
            throw new ServiceException(HttpStatus.HTTP_NOT_FOUND, "未找到对应的问卷信息");
//        BigDecimal decimal = user.getWithdrawOver().add(questionnaire.getPrice());
        BigDecimal withdrawOver = user.getWithdrawOver();
        BigDecimal decimal;
        if (ObjectUtil.isNotEmpty(withdrawOver)) {
            decimal = withdrawOver.add(questionnaire.getPrice());
        } else {
            decimal = questionnaire.getPrice();
        }
//        BigDecimal decimal = user.getWithdrawOver().add(questionnaire.getPrice());
        log.debug("用户：" + user.getNickname() + ",金额：" + decimal);
        user.setWithdrawOver(decimal);
        userService.updateById(user);
        UserTrace userTrace = new UserTrace();
        userTrace.setPhone(user.getPhone());
        userTrace.setNickname(user.getNickname());
        userTrace.setTraceSn(questionnaire.getType() + " " + questionnaire.getName());
        userTrace.setMsg(questionnaire.getType() + "-" + questionnaire.getName());
        userTrace.setSource(0);
        userTrace.setUserId(user.getId());
        userTrace.setAmount(questionnaire.getPrice());
        userTrace.setAddTime(new Date());
        userTrace.setType(1);
        userTraceMapper.insert(userTrace);
        if (ObjectUtil.isNotEmpty(user.getInviter()))
            commissionFlowForOne(questionnaire, user);
    }

    private void commissionFlowForOne(Questionnaire questionnaire, User userId) {
        User user = userService.getById(userId.getInviter());
        if (ObjectUtil.isEmpty(user))
            return;
        //上级分佣
        BigDecimal decimal = user.getWithdrawOver().add(questionnaire.getOnePrice());
        user.setWithdrawOver(decimal);
        userService.updateById(user);
        UserTrace userTrace = new UserTrace();
        userTrace.setTraceSn(questionnaire.getType() + " " + questionnaire.getName());
        userTrace.setPhone(user.getPhone());
        userTrace.setNickname(user.getNickname());
        userTrace.setSubCommission(userId.getNickname());
        userTrace.setMsg(questionnaire.getType() + "-" + questionnaire.getName());
        userTrace.setSource(1);
        userTrace.setUserId(user.getId());
        userTrace.setAmount(questionnaire.getPrice());
        userTrace.setAddTime(new Date());
        userTrace.setType(1);
        userTraceMapper.insert(userTrace);
        if (ObjectUtil.isNotEmpty(user.getInviter()))
            commissionFlowForTwo(questionnaire, user);
    }

    private void commissionFlowForTwo(Questionnaire questionnaire, User userId) {
        User user = userService.getById(userId.getInviter());
        if (ObjectUtil.isEmpty(user))
            return;
        //上上级分佣
        BigDecimal decimal = user.getWithdrawOver().add(questionnaire.getTwoPrice());
        user.setWithdrawOver(decimal);
        userService.updateById(user);
        UserTrace userTrace = new UserTrace();
        userTrace.setPhone(user.getPhone());
        userTrace.setNickname(user.getNickname());
        userTrace.setTraceSn(questionnaire.getType() + " " + questionnaire.getName());
        userTrace.setSubCommission(userId.getNickname());
        userTrace.setMsg(questionnaire.getType() + "-" + questionnaire.getName());
        userTrace.setSource(1);
        userTrace.setUserId(user.getId());
        userTrace.setAmount(questionnaire.getPrice());
        userTrace.setAddTime(new Date());
        userTrace.setType(1);
        userTraceMapper.insert(userTrace);
    }


    @Override
    public Map getSum(String phone) {
        QueryWrapper<UserTrace> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserTrace::getPhone, phone);
        List<UserTrace> userTraces = this.list(queryWrapper);
        HashMap<String, Object> hashMap = Maps.newHashMap();
        BigDecimal questionnaire = new BigDecimal(BigInteger.ZERO);
        BigDecimal subCommission = new BigDecimal(BigInteger.ZERO);
        BigDecimal withdraw = new BigDecimal(BigInteger.ZERO);
        for (UserTrace userTrace : userTraces) {
            if (userTrace.getSource() == CommonConstant.QUESTIONNAIRE)
                questionnaire = questionnaire.add(userTrace.getAmount());
            if (userTrace.getSource() == CommonConstant.SHARE)
                subCommission = subCommission.add(userTrace.getAmount());
//            if (userTrace.getSource() == 2 && userTrace.getType() == 2)
            if (userTrace.getSource() == CommonConstant.WITHDRAW ){
                withdraw = withdraw.add(userTrace.getAmount());//提现总金额

            }

        }
        hashMap.put("questionnaire", questionnaire);
        hashMap.put("subCommission", subCommission);
        hashMap.put("total", questionnaire.add(subCommission).subtract(withdraw));
        return hashMap;
    }

    @Override
    public List<UserTrace> userList(String phone) {
        return this.list(new QueryWrapper<UserTrace>().lambda()
                .eq(UserTrace::getPhone,phone)
        .orderByDesc(UserTrace::getAddTime));
    }

}
